package net.sf.brutil.v0.server;

import java.lang.reflect.Method;

import net.sf.brutil.v0.light.ErrorUtil;
import net.sf.brutil.v0.light.Pair;
import net.sf.brutil.v0.light.StringUtil;


@SuppressWarnings("unchecked")
public class ReflectionUtil {

    
    
    
    /**
     * Set the value of a field. The field name can be qualified (e.g. customer.address.town)
     */
    public static void set(Object object,String fieldName,Object value){        
        nonQualifiedSet(getNextToTop(object, fieldName),StringUtil.split(".",false, fieldName).getB(),value);
    }
    
    /**
     * Returns the next to top object using a qualified name
     * 
     */
   
    public static <E> E getNextToTop(Object object,String fieldName){
        Pair<String,String> split=StringUtil.split(".", true, fieldName);
        if (split.getB().length()==0){
            return (E)object;
        } else {
            Object root=nonQualifiedGet(object, split.getA());
            return (E)getNextToTop(root, split.getB());
        }
    }
        
        
    /**
     * Get the value of a field. The field name can be qualified (e.g. customer.address.town)
     */
    public static <E> E get(Object object,String fieldName){
        return nonQualifiedGet(getNextToTop(object, fieldName),StringUtil.split(".",false, fieldName).getB());
    }
    
    
    /**
     * Return the value of a field using its javabean's getter
     * TODO: should handle access to public field as well (i.e. without getter)
     */
    public static <E> E  nonQualifiedGet(Object object,String fieldName){
        try {
            fieldName=StringUtil.toTitleCase(fieldName);
            Method getter;
            try {
                getter=object.getClass().getMethod("get"+fieldName, new Class<?>[0]);
            } catch (NoSuchMethodException e) {
                getter=object.getClass().getMethod("is"+fieldName, new Class<?>[0]);
            }
            Object retVal=getter.invoke(object);
            return (E) retVal;
            
        } catch (Exception e){
            throw ErrorUtil.propagateError(e);
        }
    }

    
    /**
     * Set the value of a field using its javabean's setter
     * TODO: should handle access to public field as well (i.e. without getter)
     */
    public static void nonQualifiedSet(Object object,String fieldName,Object value){
        try {
            fieldName=StringUtil.toTitleCase(fieldName);
            Method setter;
               setter=object.getClass().getMethod("set"+fieldName, new Class<?>[]{value.getClass()});
            setter.invoke(object,value);
            
        } catch (Exception e){
            throw ErrorUtil.propagateError(e);
        }
    }
}
